package com.daily.DailyStudy.线程;

import java.util.concurrent.*;

/**
 * 实际的开发中，我们经常要创建子线程来做一些耗时任务，然后把任务执行结果回传给主线程使用，
 * Callable
 */
public class 子线程完成任务后把结果返回主线程 {

    public static void doTaskWithResultInWorker() {
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("Task starts");
                Thread.sleep(100);
                System.out.println("Task finished and return result");
                return "返回的内容";
            }
        };
        FutureTask<String> futureTask = new FutureTask<>(callable);
        new Thread(futureTask).start();
        try {
            System.out.println("Before futureTask.get()");
            System.out.println("Result: " + futureTask.get());
            System.out.println("After futureTask.get()");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
    //    主线程调用 futureTask.get() 方法时阻塞主线程；然后 Callable 内部开始执行，并返回运算结果；此时 futureTask.get() 得到结果，主线程恢复运行。
    //    这里我们可以学到，通过 FutureTask 和 Callable 可以直接在主线程获得子线程的运算结果，只不过需要阻塞主线程。
    //    当然，如果不希望阻塞主线程，可以考虑利用 ExecutorService，把 FutureTask 放到线程池去管理执行。
    public static void doTaskWithResultInWorkerFotExcutor() {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("Task starts");
                Thread.sleep(100);
                System.out.println("Task finished and return result");
                return "返回的内容";
            }
        };
        Future<String> task = executorService.submit(callable);
        try {
            Thread.sleep(1000);
            System.out.println("Result: " + task.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        //关闭线程池
        executorService.shutdown();
    }

    public static void main(String[] args) {
        doTaskWithResultInWorker();
        System.out.println("--------- 第二种方法使用线程池 ---------");
        doTaskWithResultInWorkerFotExcutor();
    }
}
